# -*- coding: utf-8 -*-

import os
from io import BytesIO
from pathlib import Path
from typing import Dict, Iterator, List, Literal, Tuple, Union, Sequence, Optional
from multiprocessing import Pool, cpu_count, ProcessError

import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont, ImageFile
from rich.progress import Progress

from .ConsoleIO import prt, format_ipt, bool_str
from .Constants import (
    ADAPT,
    BINARY_BW,
    BWIZE_TYPE,
    DITHERING_BW,
    FILL,
    GRAY_BW,
    MC_FONT,
    MC_IMAGE_PALETTE2,
    MC_RGB_DROP_LIST,
    PALETTE_IMAGE,
    RESIZEMODE_TYPE,
    RGB_CHAR_TABLE,
    RGB_CHAR_TABLE2,
    FILE_SAVE_SUFFIX,
)


# 图片大小调整
def resize_image(
    img: Image.Image,
    wide: int,
    height: int,
    resizemod: RESIZEMODE_TYPE = FILL,
) -> Image.Image:
    """
    图片大小调整
    :param img: Image对象
    :param wide: 宽
    :param height: 高
    :param resizemod: 填充模式[填充，适应]
    :return: 调整后的Image对象
    """
    width_init: int = img.width
    height_init: int = img.height
    if width_init / height_init != wide / height:
        if resizemod == ADAPT:
            width_4_operation = width_init
            height_4_operation = height_init
            if height_init > width_init * height / wide:
                wide = int(height * width_init / height_init)
            else:
                height = int(wide * height_init / width_init)
        else:
            if height_init > width_init * height / wide:
                height_4_operation = width_init * height / wide
                width_4_operation = width_init
            else:
                width_4_operation = height_init * wide / height
                height_4_operation = height_init
    else:
        width_4_operation = width_init
        height_4_operation = height_init
    return img.crop(
        (
            int((width_init - width_4_operation) / 2),
            int((height_init - height_4_operation) / 2),
            int(width_4_operation + (width_init - width_4_operation) / 2),
            int(height_4_operation + (height_init - height_4_operation) / 2),
        )
    ).resize((wide, height))


# grb颜色混合
def coulour_mix(
    colour_a: Tuple[int, int, int],
    colour_b: Tuple[int, int, int],
    percentage: float = 0.5,
) -> tuple:
    """
    grb颜色混合
    :param rgba: rgb A
    :param rgbb: rgb B
    :param percentage: rgb A所占比重[0, 1]
    :return:
    """
    r = int(colour_a[0] - (colour_a[0] - colour_b[0]) * (1 - percentage))
    g = int(colour_a[1] - (colour_a[1] - colour_b[1]) * (1 - percentage))
    b = int(colour_a[2] - (colour_a[2] - colour_b[2]) * (1 - percentage))
    return r, g, b


# 获取文字长宽
def get_text_disp_size(text_: str, font_: ImageFont.FreeTypeFont = MC_FONT):
    """
    获取文字的长宽
    """
    canvas = Image.new("RGB", (2048, 2048))
    ImageDraw.Draw(canvas).text(
        xy=(0, 0),
        text=text_,
        font=font_,
        fill=(255, 255, 255),
    )
    bbox = canvas.getbbox()
    if bbox is None:
        return 0, 0
    return bbox[2] - bbox[0], bbox[3] - bbox[1]


# 获取MC显示宽度
# @jit(nopython=True)
def get_mc_display_width(text_: str):
    return sum([get_text_disp_size(i)[0] + 2 for i in text_.replace(" ", "a")])


# 获取MC显示宽度检字表
# @jit(nopython=True)
def get_mc_display_width_table(text_: str) -> Dict[str, int]:
    return {i: get_text_disp_size(i)[0] + 2 for i in text_}


# 图片转彩条
def image2mcstring(
    img: Image.Image,
    additional_text: str = "",
) -> str:
    img = resize_image(img, img.width, img.height - img.height % 4)

    seted_image = Image.new("RGB", (img.width, img.height // 4), (0, 0, 0))
    # 读取原像素，合并垂直像素，重构图片
    for y in range(img.height // 4):
        for x in range(img.width):
            # 垂直四像素合并
            pixels: Tuple[
                Tuple[int, int, int],
                Tuple[int, int, int],
                Tuple[int, int, int],
                Tuple[int, int, int],
            ] = (
                img.getpixel((x, y * 4)),  # type: ignore
                img.getpixel((x, y * 4 + 1)),
                img.getpixel((x, y * 4 + 2)),
                img.getpixel((x, y * 4 + 3)),
            )
            seted_image.putpixel(
                (x, y),
                tuple(
                    [
                        (pixels[0][i] + pixels[1][i] + pixels[2][i] + pixels[3][i]) // 4
                        for i in range(3)
                    ]
                ),
            )
    # 重设调色板
    seted_image = seted_image.quantize(palette=PALETTE_IMAGE).convert("RGB")

    # 转换为字符串内容
    front_space = " " * (img.width // 10)
    final_result = "§l" + front_space

    for y in range(seted_image.height):
        old_colour = ""
        for x in range(seted_image.width):
            new_colour, new_char = RGB_CHAR_TABLE[tuple(seted_image.getpixel((x, y)))]  # type: ignore

            final_result += (new_colour if new_colour != old_colour else "") + new_char
            old_colour = new_colour
        final_result += "\\n" + front_space

    return final_result + additional_text


# 转为黑白图片
def to_black_white_img(
    img: Image.Image, mode: BWIZE_TYPE = DITHERING_BW, threshold: int = 200
) -> Image.Image:
    """
    转为黑白图片
    :param img: Image类对象
    :param mode: BINARY_BW|GRAY_BW|DITHERING_BW
    :param threshold: 若mode为 BINARY_BW 则启用：二值化分界点
    :return: 调整后图像
    """
    if mode == DITHERING_BW:
        return img.convert("1")

    elif mode == BINARY_BW:
        # 自定义灰度界限，大于这个值为黑色，小于这个值为白色
        # 图片二值化
        return img.convert("L").point([int(i >= threshold) for i in range(256)], "1")
    elif mode == GRAY_BW:
        return img.convert("L")
    else:
        raise ValueError("转换模式须为 BINARY_BW | GRAY_BW | DITHERING_BW")


# 黑白图片转盲文字符画
def bw_img_to_str(img: Image.Image) -> str:
    """
    黑白图片转盲文字符画
    :param img: Image类对象
    :return: 字符串
    """
    img = resize_image(img, img.width - img.width % 2, img.height - img.height % 4)

    strlist = [["" for _ in range(img.width // 2)] for _ in range(img.height // 4)]

    finalstr = ""
    for y in range(img.height):
        for x in range(img.width):
            a = img.getpixel((x, y))
            strlist[y // 4][x // 2] += "0" if a == 0 else "1"
    for i in range(len(strlist)):
        for ii in range(len(strlist[i])):
            finalstr += chr(
                10240
                + int(
                    strlist[i][ii][:5:-1]
                    + strlist[i][ii][5::-2]
                    + strlist[i][ii][4::-2],
                    2,
                )
            )
        finalstr += "\n"
    return finalstr


# 转彩色盲文字符串
def img_to_braille_rgbstr(
    img: Image.Image,
    other_addition: str = "",
) -> str:
    """
    转彩色字符串
    :param img: Image类对象
    :return: 字符串
    """
    # rgb原图
    img = resize_image(img, img.width, img.height - img.height % 4)
    # 拉宽1.5倍
    img = img.resize((int(img.width * 0.7), img.height))

    # rgb取色参考图
    seted_image = Image.new("RGB", (img.width, img.height // 4), (0, 0, 0))

    # 读取原像素，合并垂直像素，重构图片
    for y in range(img.height // 4):
        for x in range(img.width):
            # 垂直四像素合并
            pixels: Tuple[
                Tuple[int, int, int],
                Tuple[int, int, int],
                Tuple[int, int, int],
                Tuple[int, int, int],
            ] = (
                img.getpixel((x, y * 4)),  # type: ignore
                img.getpixel((x, y * 4 + 1)),
                img.getpixel((x, y * 4 + 2)),
                img.getpixel((x, y * 4 + 3)),
            )
            seted_image.putpixel(
                (x, y),
                tuple(
                    [
                        (pixels[0][i] + pixels[1][i] + pixels[2][i] + pixels[3][i]) // 4
                        for i in range(3)
                    ]
                ),
            )
    # 抖动、减色

    seted_image = seted_image.quantize(palette=MC_IMAGE_PALETTE2).convert("RGB")
    # 转换为str
    # space = " " * round(img.width / 11)
    # finalstr = "§l" + space
    finalstr = ""
    for y in range(seted_image.height):
        previous_mc_colour = ""
        for x in range(seted_image.width):
            # 计算盲文点
            target_rgb: tuple = seted_image.getpixel((x, y))  # type: ignore
            mc_colour, char_, anti_target_rgb = RGB_CHAR_TABLE2[target_rgb]

            braille_str = [
                (
                    char_
                    if np.sum(
                        np.square(
                            np.array(img.getpixel((x_, y_)))[:3]
                            - np.array(target_rgb)[:3]
                        )
                    )
                    < np.sum(
                        np.square(
                            np.array(img.getpixel((x_, y_)))[:3]
                            - np.array(anti_target_rgb)[:3]
                        )
                    )
                    else RGB_CHAR_TABLE2[anti_target_rgb][1]
                )
                for x_, y_ in (
                    (x, y * 4 + 3),
                    (x, y * 4 + 2),
                    (x, y * 4 + 1),
                    (x, y * 4),
                )
            ]

            # 拼接rgb格式化字符
            finalstr += mc_colour if mc_colour != previous_mc_colour else ""
            # 拼接盲文点
            finalstr += chr(
                10240
                + int("".join([braille_str[i] for i in (0, 0, 1, 2, 3, 1, 2, 3)]), 2)
            )

            previous_mc_colour = mc_colour
        # finalstr += r"\n" + space
        finalstr += r"\n"
    # if position == "bottom" and subtitle != "":
    #     # # round((img.width * (5宽+2间隔) - get_mc_display_width(subtitle))/2居中/(6空格宽+2间隔)-0修正)
    #     # # finalstr += ' ' * round((img.width * 4.5)/8) + subtitle
    #     finalstr += (
    #         " " * round((img.width * 7 - get_mc_display_width(subtitle)) / 16)
    #         + color
    #         + subtitle
    #     )

    return finalstr + other_addition  # + r"\n" * round(seted_image.height * 0.7 + 2)


# 转彩色盲文字符串[矩阵]
def img_to_colored_braille_str_matrix(img: Image, subtitle: str = '', position: str = 'bottom', color: str = ''):
    """
       转彩色盲文字符串
       :param img: Image类对象
       :param subtitle: 字幕
       :param position: 字幕位置
       :param color: 字幕颜色
       :return: 字符串
       """

    # 盲文点参考图,提前取点减少分辨率损失
    # 0.6, 0.97 用于抵消转换为mc文本后导致的变形
    img2 = img.resize((int(int(img.width * 0.6) * 2), int(img.height * 0.97)))
    # 行像素取整
    img2 = resize_image(img2, img2.width, img2.height - img2.height % 4)
    # 取消缩限，尝试
    # img2 = img2.quantize(palette=MC_IMAGE_PALETTE2)
    img2 = img2.convert('RGB')
    # 压缩
    img = img.resize((int(img.width * 0.6), int(img.height * 0.97)))
    # rgb原图
    img = resize_image(img, img.width, img.height - img.height % 4)

    # rgb取色参考图
    # 读取原像素，合并垂直像素，重构图片
    img_array = np.array(img).astype(np.uint16)
    img_array2 = np.array(img).astype(np.uint8)

    img_array_list = []
    for i in [img_array[i::4] for i in range(4)]:
        img_array_list.append(sum(i[:, :, ii] for ii in range(3)))

    img_array = sum(img_array_list)
    image_rebuild = np.zeros((img.height // 4, img.width, 3), dtype=np.uint8)

    image_rebuild[:, :, 0] = sum(img_array2[i::4, :, 0] / (img_array / img_array_list[i]) for i in range(4))
    image_rebuild[:, :, 1] = sum(img_array2[i::4, :, 1] / (img_array / img_array_list[i]) for i in range(4))
    image_rebuild[:, :, 2] = sum(img_array2[i::4, :, 2] / (img_array / img_array_list[i]) for i in range(4))
    image_rebuild = Image.fromarray(image_rebuild)


    # 抖动、减色
    image_rebuild = image_rebuild.quantize(palette=MC_IMAGE_PALETTE2)
    image_rebuild = image_rebuild.convert('RGB')

    # 盲文点参考图
    img2_array = np.array(img2).astype(np.uint16)

    # 垂直合并后矩阵
    img_array = np.array(image_rebuild)
    # 复制填充为img2等尺寸
    img_array1 = np.zeros(img2_array.shape, dtype=np.int16)
    # 互补色
    img_array2 = np.zeros(img2_array.shape, dtype=np.int16)

    # 像素点取反标志
    bin_array = np.zeros((img2.height, img2.width), dtype=np.int16)
    # 当前rgb默认像素点状态
    bin_array2 = np.zeros((img2.height, img2.width), dtype=np.uint8)
    for y in range(image_rebuild.height):
        for x in range(image_rebuild.width):
            temp = RGB_CHAR_TABLE2[tuple(img_array[y, x])]
            # image_array2[y, x] = temp[2]
            img_array1[y*4:y*4+4, x*2:x*2+2] = img_array[y, x]
            img_array2[y*4:y*4+4, x*2:x*2+2] = temp[2]
            bin_array2[y*4:y*4+4, x*2:x*2+2] = temp[1]

    # 计算三维距离(去除开方过程, /3防止数据溢出）
    # 与原色距离
    bin_temp1 = np.power(img2_array - img_array1, 2)/3
    # bin_temp1 = bin_temp1[:, :, 0] + bin_temp1[:, :, 1] + bin_temp1[:, :, 2]
    # 与补色距离
    bin_temp2 = np.power(img2_array - img_array2, 2)/3
    # bin_temp2 = bin_temp2[:, :, 0] + bin_temp2[:, :, 1] + bin_temp2[:, :, 2]
    # 得到差值（正>保持，负>像素点状态取反）
    # bin_array = bin_temp2 - bin_temp1
    # 合并计算过程
    bin_array = bin_temp2[:, :, 0] + bin_temp2[:, :, 1] + bin_temp2[:, :, 2] - bin_temp1[:, :, 0] - bin_temp1[:, :, 1] - bin_temp1[:, :, 2]

    # 正负转为[0, 1]二值化（0 需要取反，1 保持）
    lam = np.vectorize(lambda x: 1 if x >= 0 else 0)
    bin_array = lam(bin_array)

    # 局部取反
    #计算全部取反后结果
    bin_array3 = 1 - bin_array
    bin_array4 = 1 - bin_array2
    # 合并计算结果
    bin_array = bin_array2 * bin_array + bin_array4 * bin_array3

    # 计算盲文点
    bin_array_f = np.zeros(bin_array.shape, dtype=np.uint8)

    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] + bin_array[3::4, 1::2]

    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] * 2
    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] + bin_array[3::4, 0::2]

    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] * 2
    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] + bin_array[2::4, 1::2]

    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] * 2
    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] + bin_array[1::4, 1::2]

    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] * 2
    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] + bin_array[0::4, 1::2]

    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] * 2
    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] + bin_array[2::4, 0::2]

    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] * 2
    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] + bin_array[1::4, 0::2]

    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] * 2
    bin_array_f[::4, ::2] = bin_array_f[::4, ::2] + bin_array[0::4, 0::2]

    # 转换为str
    space = " " * round(img.width / 8)
    final_str = "§l" + space
    for y in range(image_rebuild.height):
        old_rgb = ''
        for x in range(image_rebuild.width):
            # 拼接rgb格式化字符
            new_rgb, _, _ = RGB_CHAR_TABLE2[image_rebuild.getpixel((x, y))]
            final_str += new_rgb if new_rgb != old_rgb else ""
            # 拼接盲文点
            # final_str += chr(10240 + int(bin_str, 2))
            final_str += chr(10240 + int(bin_array_f[y*4, x*2]))

            old_rgb = new_rgb
        # final_str += r"\n" + space
        final_str += r"\n" + space
    if position == 'bottom' and subtitle != '':
        # round((self.width * (5宽+2间隔) - get_mc_display_width(subtitle))/2居中/(6空格宽+2间隔)-0修正)
        final_str += ' ' * round((img.width * 7 - get_mc_display_width(subtitle))/16) + color + subtitle
    final_str += r'\n' * round(image_rebuild.height * 0.7+2)
    return final_str

# 方便并行计算的函数


def single_image_2_bandstring_coloured(
    idx_: int,
    image_data: bytes,
    image_mode: str,
    image_size_x: int,
    image_size_y: int,
    additon_text: str = "",
) -> Tuple[int, str]:
    return idx_, image2mcstring(
        Image.frombytes(
            mode=image_mode, size=(image_size_x, image_size_y), data=image_data
        ),
        additon_text,
    )


def single_image_2_string_coloured(
    idx_: int,
    image_data: bytes,
    image_mode: str,
    image_size_x: int,
    image_size_y: int,
    additon_text: str = "",
) -> Tuple[int, str]:
    return idx_, img_to_colored_braille_str_matrix(
        Image.frombytes(
            mode=image_mode, size=(image_size_x, image_size_y), data=image_data
        ),
        additon_text,
    )


def single_image_2_string_bw(
    idx_: int,
    image_data: bytes,
    image_mode: str,
    image_size_x: int,
    image_size_y: int,
    additon_text: str = "",
) -> Tuple[int, str]:
    return (
        idx_,
        bw_img_to_str(
            to_black_white_img(
                Image.frombytes(
                    mode=image_mode, size=(image_size_x, image_size_y), data=image_data
                ),
            )
        )
        + additon_text,
    )


# 图形列表转字符串列表
def image_list_2_string(
    image_list: Sequence[Tuple[bytes, str, int, int],],
    is_coloured: bool = True,
    is_coloured_band: bool = False,
    rolling_length: int = 20,
    flashing: bool = False,
) -> Iterator[Tuple[int, str]]:
    """
    图片字符串列表
    :param image_list:
    :return:
    """
    if rolling_length <= 5:
        rolling_length = 10
    rolling_text = "算法提供：AmmeIia   整体封装：金羿   特别鸣谢：玉衡Alioth   "
    text_length = len(rolling_text)
    length_table = get_mc_display_width_table(rolling_text)

    rolling_text_length_table = {
        i: sum([length_table[j] for j in i])
        for i in [
            (rolling_text * (rolling_length // text_length + 2))[
                text_length
                - frame_number % text_length : rolling_length
                + text_length
                - frame_number % text_length
            ]
            for frame_number in range(text_length)
        ]
    }

    max_length = max(rolling_text_length_table.items(), key=lambda x: x[1])[1]

    k = 0
    rolling_text_list = []
    for i, j in rolling_text_length_table.items():
        rolling_text_list.append(
            "§r"
            + (("§0" + round((max_length - j) / 6) * "|") if j < max_length else "")
            + (MC_RGB_DROP_LIST[k % 52] if flashing else "§7")
            + i
            + (("§0" + round((max_length - j) / 6) * "|") if j < max_length else "")
        )
        k += 1

    prt("样式表处理完成！")

    total_length = len(image_list)

    with Progress() as progress:
        total_task_start = progress.add_task(
            "[#0089F2 on #121110]处理图片", total=total_length
        )

        # if isinstance(image_list[0][0], Tuple):
        # yield 0, (
        #     img_to_braille_rgbstr(image_list[i][0])
        #     if is_coloured
        #     else bw_img_to_str(to_black_white_img(image_list[i][0]))
        # ) + rolling_text_list[i // 3 % text_length]

        with Pool(processes=cpu_count() - 2) as pool:
            pool_results = []
            for i in range(total_length):
                pool_results.append(
                    pool.apply_async(
                        (
                            (
                                single_image_2_bandstring_coloured
                                if is_coloured_band
                                else single_image_2_string_coloured
                            )
                            if is_coloured
                            else single_image_2_string_bw
                        ),
                        args=(
                            i,
                            *image_list[i],
                            rolling_text_list[i // 3 % text_length],
                        ),
                    )
                )

            for i in range(total_length):
                idx_, stt_ = pool_results[i].get()
                if idx_ == i:
                    yield idx_, stt_
                else:
                    if format_ipt(
                        "[#F03432 on #121110]进程顺序可能传递错误，是否继续？[#F2F4F6 on #121110]（视频部分帧可能无法对齐，理论上此处错误不应发生，很稀有，因此拜托告诉开发者，谢谢了！）",
                        bool_str,
                        "请输入正确的布尔格式。",
                    )[1]:
                        yield idx_, stt_
                    else:
                        raise ProcessError("进程顺序传递错误")

                progress.update(
                    total_task_start,
                    advance=1,
                    description="[#0089F2 on #121110]处理图片 {}/{}".format(
                        i,
                        total_length,
                    ),
                )
        #     yield single_image_2_string_coloured(
        #         i,
        #         *image_list[i],
        #         additon_text=
        #     )
        # else:

        # yield 0, (
        #     img_to_braille_rgbstr(image_list[i][0])
        #     if is_coloured
        #     else bw_img_to_str(to_black_white_img(image_list[i][0]))
        # ) + rolling_text_list[i // 3 % text_length]

        # for i in range(total_length):

        #     yield single_image_2_string_coloured(
        #         i,
        #         *image_list[i],
        #         additon_text=rolling_text_list[i // 3 % text_length],
        #     )

        #     progress.update(
        #         total_task_start,
        #         advance=1,
        #         description="[#0089F2 on #121110]处理图片 {}/{}".format(
        #             i,
        #             total_length,
        #         ),
        #     )
        # for i in range(total_length):

        #     yield 0, (
        #         img_to_braille_rgbstr(image_list[i])
        #         if is_coloured
        #         else bw_img_to_str(to_black_white_img(image_list[i]))
        #     ) + rolling_text_list[i // 3 % text_length]

        #     progress.update(
        #         total_task_start,
        #         advance=1,
        #         description="[#0089F2 on #121110]处理图片 {}/{}".format(
        #             i, total_length, image_list[i]
        #         ),
        #     )


# 视频帧提取
def vedio_frame_split(
    vedio_path: str,
    max_resolving_fps: int,
    resize: bool = False,
    width: int = 0,
    height: int = 0,
    resize_mode: RESIZEMODE_TYPE = FILL,
    output_path: Optional[Path] = None,
    startup_clear: bool = True,
) -> Tuple[
    int,
    List[
        Tuple[
            bytes,
            str,
            int,
            int,
        ]
    ],
]:
    """
    视频帧提取
    :param vedio_path: 视频文件路径
    :param max_resolving_fps: 最大帧率
    :param resize: 是否调整大小
    :param width: 宽
    :param height: 高
    :param resize_mode: 填充模式[填充，适应]
    :param output_path: 输出路径
    :param startup_clear: 是否生成前提前清空输出文件夹，当且仅当output_path启用时启用
    :return: 提取帧总数, 帧图像列表
    """
    # 获取剪辑对象
    main_video_capture = cv2.VideoCapture(vedio_path)

    if output_path:
        # 处理临时目录
        output_path.mkdir(parents=True, exist_ok=True)
        if startup_clear:
            for i in output_path.iterdir():
                os.remove(i)

    total_frame_count = int(main_video_capture.get(cv2.CAP_PROP_FRAME_COUNT))
    video_fps = main_video_capture.get(cv2.CAP_PROP_FPS)

    frame_choose = max_resolving_fps / video_fps if video_fps > max_resolving_fps else 1

    # 按帧读取视频，成功为success返回True，为img返回三维矩阵
    success, frame_img = main_video_capture.read()

    frame_count = 0
    img_count = 0

    prt(
        "正在提取视频帧\n原视频数据({fps}fps {count}帧)\n提取参数(最大帧率{max_fps}fps {frames}帧{additional})".format(
            fps=video_fps,
            count=total_frame_count,
            max_fps=max_resolving_fps,
            frames=int(total_frame_count * frame_choose),
            additional=f" {width}*{height}最大分辨率" if resize else "",
        )
    )

    result_image_list: List[
        Tuple[
            bytes,
            str,
            int,
            int,
        ]
    ] = []

    with Progress() as progress:
        total_task_start = progress.add_task(
            "[#0089F2 on #121110]提取视频帧",
            total=(total_frame_count * frame_choose - 1),
        )

        while success:
            if frame_count > 1:
                frame_count -= 1
                image_piece = Image.fromarray(
                    cv2.cvtColor(frame_img, cv2.COLOR_BGR2RGB)
                )

                if resize:
                    image_piece = resize_image(image_piece, width, height, resize_mode)

                result_image_list.append(
                    (
                        cache_data := image_piece.tobytes(),
                        cache_mode := image_piece.mode,
                        *(cache_size := image_piece.size),
                    )
                )

                if output_path:
                    (
                        output_path / "{}.{}.RAW".format(img_count, FILE_SAVE_SUFFIX)
                    ).write_bytes(cache_data)
                    (
                        output_path / "{}.{}.COT".format(img_count, FILE_SAVE_SUFFIX)
                    ).write_text(
                        "{}\n{}\n{}".format(cache_mode, *cache_size),
                        encoding="utf-8",
                    )
                progress.track
                progress.update(total_task_start, advance=1)
                img_count += 1

            #             cv2.imencode(".bmp", frame_img)[1].tofile(
            #                 os.path.join(output_path, f"{img_count}.bmp")
            #             )
            #             if resize:
            #                 image_ = Image.open(os.path.join(output_path, f"{img_count}.bmp"))
            #                 image_ = imgresize(image_, width, height, resize_mode)
            #                 image_.save(os.path.join(output_path, f"{img_count}.bmp"))

            frame_count += frame_choose
            if frame_count > 1:
                success, frame_img = main_video_capture.read()
            else:
                success = main_video_capture.grab()

    if output_path:
        (output_path / "CACHE_IDX").write_text(
            str(img_count),
            encoding="utf-8",
        )

    prt("提取完成")
    return img_count, result_image_list
